﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CommClass
{
    #region IC卡

    /// <summary>
    /// IC卡
    /// </summary>
    class ICCard
    {
        /// <summary>
        /// IC卡内部编码
        /// </summary>
        private int cardID;
        public int CardID
        {
            get { return cardID; }
            set { cardID = value; }
        }

        /// <summary>
        /// IC卡编号
        /// </summary>
        private string cardNumber;
        public string CardNumber
        {
            get { return cardNumber; }
            set { cardNumber = value; }
        }

        /// <summary>
        /// IC卡序列号（4字节）
        /// </summary>
        private string cardSN;
        public string CardSN
        {
            get { return cardSN; }
            set { cardSN = value; }
        }

        /// <summary>
        /// IC卡备注
        /// </summary>
        private string remark;
        public string Remark
        {
            get { return remark; }
            set { remark = value; }
        }
    }

    //IC卡块项集合（字节数组）
    class ICItems
    {
        //字节数
        private int count;
        public int Count
        {
            get { return count; }
        }

        //ToString输出字符串的分隔符
        private string separator;
        public string Separator
        {
            get { return separator; }
            set { separator = value; }
        }

        private byte[] _items;

        public byte this[int index]
        {
            get { return _items[index]; }
            set { _items[index] = value; }
        }

        public ICItems(int ItemCount)
        {
            count = ItemCount;
            _items = new byte[count];
            separator = "";
        }

        /// <summary>
        /// 转换为字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string result = String.Format("{0:x2}", _items[0]);
            for (int i = 1; i < Count; i++)
            {
                result = result + separator + String.Format("{0:x2}", _items[i]);
            }
            return result;
        }

        /// <summary>
        /// 复制到字节数组
        /// </summary>
        /// <param name="buf">要复制到的数组</param>
        public void CloneTo(byte[] buf)
        {
            for (int i = 0; i < count; i++)
            {
                buf[i] = _items[i];
            }
        }

        /// <summary>
        /// 从字节数组复制
        /// </summary>
        /// <param name="buf">要复制的数组</param>
        public void CloneFrom(byte[] buf)
        {
            int ByteCount;
            ///todo: 需要判断如果buf的最大长度小于count的时候
            ByteCount = count;
            for (int i = 0; i < ByteCount; i++)
            {
                _items[i] = buf[i];
            }
        }
    }

    //IC卡块
    class ICBlock
    {
        private int ItemCount = 16;

        private ICItems items;
        public ICItems Items
        {
            get
            {
                if (items == null)
                    items = new ICItems(ItemCount);
                return items;
            }
            set { items = value; }
        }
    }

    // IC卡扇区
    class ICSector
    {
        //KeyA
        private ICItems keyA = new ICItems(6);
        public ICItems KeyA
        {
            get { return keyA; }
            set { keyA = value; }
        }

        //AccessBits
        private ICItems accessBits = new ICItems(4);
        public ICItems AccessBits
        {
            get { return accessBits; }
            set { accessBits = value; }
        }

        //KeyB
        private ICItems keyB = new ICItems(6);
        public ICItems KeyB
        {
            get { return keyB; }
            set { keyB = value; }
        }

        // 块数量
        private int blockCount;
        public int BlockCount
        {
            get { return blockCount; }
        }

        /// <summary>
        /// 构造函数，给KeyA，KeyB赋初值
        /// </summary>
        /// <param name="_blockCount">每个扇区的块数</param>
        public ICSector(int _blockCount)
        {
            blockCount = _blockCount;
            for (int i = 0; i < keyA.Count; i++)
            {
                keyA[i] = 0xff;
            }
            for (int i = 0; i < keyB.Count; i++)
            {
                keyB[i] = 0xff;
            }
        }

        public ICBlock GetBlock(int index)
        {
            ICBlock _block = new ICBlock();
            return _block;
        }
    }

    //MF1 IC S70卡
    class ICS70
    {
        private IntPtr cardReaderHandle;

        //读取设备的handle
        public void GetDeviceHandle(IntPtr _Handle)
        {
            cardReaderHandle = _Handle;
        }

        ////卡序列号
        //public ICItems SerialNumber
        //{
        //    get { return GetSerialNumber(); }
        //}

        //卡扇区数量
        private int sectorCount;
        public int SectorCount
        {
            get { return sectorCount; }
        }

        //当前扇区索引
        private byte sectorIndex;
        public byte SectorIndex
        {
            get { return sectorIndex; }
            set { sectorIndex = value; }
        }

        /// <summary>
        /// 构造函数
        /// 设定扇区为40个
        /// </summary>
        public ICS70()
        {
            //S70卡为40个扇区
            sectorCount = 40;
            sectorIndex = 0;
        }

        /// <summary>
        /// 取得块数量
        /// </summary>
        /// <param name="_blockIndex">扇区索引</param>
        /// <returns>块数量。如果块索引超出卡范围返回0</returns>
        public byte GetBlockCount(byte _sectorIndex)
        {
            byte result;
            //第1－31扇区有4个块（除第1扇区的块0为厂商固化代码，不可改写外，其他扇区块0－块2均为用户数据区）。块3包含了该扇区的密码A(6 个字节)、存取控制(4 个字节)、密码B(6 个字节)
            if (_sectorIndex <= 31)
                result = 4;
            else
            {
                //第32－32扇区有16个块（块0－块14为用户数据区。块15包含了该扇区的密码A(6 个字节)、存取控制(4 个字节)、密码B(6 个字节)）
                if (_sectorIndex <= 39)
                    result = 16;
                else
                    result = 0;
            }
            return result;
        }

        /// <summary>
        /// 扇区
        /// </summary>
        public ICSector GetSector(byte _index)
        {
            ICSector S70Sector = new ICSector(GetBlockCount(_index));
            return S70Sector;
        }

        /// <summary>
        /// 取得绝对块索引号
        /// </summary>
        /// <param name="_sectorIndex">扇区索引</param>
        /// <param name="_blockIndex">块索引</param>
        /// <returns>返回绝对块索引号</returns>
        private byte GetAbsolutBlockIndex(byte _sectorIndex, byte _blockIndex)
        {
            byte result = 0;
            if (_sectorIndex < 32)
            {
                result = (byte)(_sectorIndex * 4 + _blockIndex);
            }
            else
            {
                result = (byte)(128 + (_sectorIndex - 32) * 16 + _blockIndex);
            }

            return result;
        }

        

     
    }
    #region 读卡操作
    ///// <summary>
    ///// 取得块数据
    ///// </summary>
    ///// <param name="_blockIndex">块索引</param>
    ///// <returns></returns>
    //public ICItems GetBlockValue(byte _blockIndex)
    //{
    //    ICItems result = new ICItems(16);

    //    byte[] buf = new byte[16];
    //    byte[] password = new byte[6];

    //    for (int i = 0; i < 6; i++)
    //    {
    //        password[i] = GetSector(sectorIndex).KeyA[i];
    //    }

    //    if (ICDLL.API_MF_Read(cardReaderHandle, 0, 0x00, GetAbsolutBlockIndex(SectorIndex, _blockIndex), 1, password, buf) != 0)
    //        MessageBox.Show(buf[0].ToString());
    //    for (int i = 0; i < buf.Length; i++)
    //    {
    //        result[i] = buf[i];
    //    }
    //    return result;
    //}

    ///// <summary>
    ///// 写块数据
    ///// </summary>
    ///// <param name="_blockIndex">块索引</param>
    ///// <returns></returns>
    //public Boolean SetBlockValue(byte _blockIndex, ICItems _blockValue)
    //{
    //    Boolean result = true;

    //    byte[] buf = new byte[16];
    //    byte[] password = new byte[6];

    //    for (int i = 0; i < 6; i++)
    //    {
    //        password[i] = GetSector(sectorIndex).KeyA[i];
    //    }

    //    for (int i = 0; i < _blockValue.Count; i++)
    //    {
    //        buf[i] = _blockValue[i];
    //    }

    //    if (ICDLL.API_MF_Write(cardReaderHandle, 0, 0x00, GetAbsolutBlockIndex(sectorIndex, _blockIndex), 1, password, buf) != 0)
    //    {
    //        result = false;
    //        MessageBox.Show(buf[0].ToString());
    //    }
    //    return result;
    //}

    //public ICItems GetSectorKeyA(byte _sectorIndex)
    //{
    //    ICItems result = new ICItems(16);
    //    byte[] buf = new byte[16];
    //    byte[] password = new byte[6];

    //    for (int i = 0; i < 6; i++)
    //    {
    //        password[i] = GetSector(_sectorIndex).KeyA[i];
    //    }
    //    if (ICDLL.API_MF_Read(cardReaderHandle, 0, 0x00, 255, 1, password, buf) != 0)
    //    {
    //        MessageBox.Show(buf[0].ToString());
    //    }
    //    for (int i = 0; i < buf.Length; i++)
    //    {
    //        result[i] = buf[i];
    //    }
    //    return result;
    //}
    #endregion

    #endregion

    #region 读卡器
    class CardReader
    {
        #region 导入读卡器函数
        /// <summary>
        /// 打开指定端口和波特率的串口
        /// </summary>
        /// <param name="nCom">串口号</param>
        /// <param name="nBaudrate">波特率</param>
        /// <returns>成功返回串口的句柄，否则返回0(INVALID_HANDLE_VALUE)</returns>
        [DllImport("All.dll", EntryPoint = "API_OpenComm")]
        static extern IntPtr API_OpenComm(int nCom, int nBaudrate);

        //关闭指定串口
        /// <summary>
        /// 关闭指定串口
        /// </summary>
        /// <param name="commHandle">commHandle-指定的串口句柄</param>
        /// <returns>成功返回1否则为0</returns>
        [DllImport("All.dll", EntryPoint = "API_CloseComm")]
        static extern Boolean API_CloseComm(IntPtr commHandle);


        [DllImport("All.dll", EntryPoint = "API_ControlBuzzer")]
        static extern int API_ControlBuzzer(IntPtr commHandle, int DeviceAddress, byte freq, byte duration, ref byte buffer);

        /// <summary>
        /// 控制led的工作方式（最多可控制两个LED）
        /// </summary>
        /// <param name="commHandle">串口句柄</param>
        /// <param name="DeviceAddress">要通讯的设备地址号，范围从0－255</param>
        /// <param name="freq">LED的周期（一个周期为20ms,最多为50）</param>
        /// <param name="duration">亮灯次数（状态循环的次数）</param>
        /// <param name="buffer">buffer[0]: 返回状态，具体含义见附表。成功返回0否则为非0, 具体含义见附表。</param>
        /// <returns></returns>
        [DllImport("All.dll", EntryPoint = "API_ControlLED")]
        static extern int API_ControlLED(IntPtr commHandle, int DeviceAddress, byte freq, byte duration, ref byte buffer);



        /// <summary>
        /// 读取读写器的版本号
        /// </summary>
        /// <param name="commHandle">串口句柄</param>
        /// <param name="DeviceAddress">要通讯的设备地址号，范围从0－255</param>
        /// <param name="VersionNum">VersionNum[0-15]: 返回版本号，共16字节。成功返回0否则为非0, 具体含义见附表。</param>
        /// <returns></returns>
        [DllImport("All.dll", EntryPoint = "API_GetVersionNum")]
        static extern int API_GetVersionNum(IntPtr commHandle, int DeviceAddress, byte[] VersionNum);

        /// <summary>
        /// 读取由厂家预设的1个字节的读卡器地址和8个字节序列号.
        /// </summary>
        /// <param name="commHandle">串口句柄</param>
        /// <param name="DeviceAddress">设备地址</param>
        /// <param name="buffer">要通讯的设备地址号，范围从0－255
        /// 如果成功，buffer[0]: 读写器地址，buffer[1-8]: 8个字节的读写器序列号
        /// 如果失败，buffer[0]: 返回状态，具体含义见附表。
        /// 成功返回0否则为非0, 具体含义见附表。
        /// </param>
        /// <returns></returns>
        [DllImport("All.dll", EntryPoint = "API_GetSerNum")]
        static extern int API_GetSerNum(IntPtr commHandle, int DeviceAddress, byte[] buffer);

        [DllImport("All.dll", EntryPoint = "API_SetSerNum")]
        static extern int API_SetSerNum(IntPtr commHandle, int DeviceAddress, byte[] NewValue, ref byte buffer);


        /// <summary>
        ///   集成寻卡，防冲突，选卡，验证密码，读卡等操作，一个命令完成读卡操作。
        ///   发送ISO14443 A 读卡指令
        /// </summary>
        /// <param name="commHandle">串口句柄</param>
        /// <param name="DeviceAddress">要通讯的设备地址号，范围从0－255</param>
        /// <param name="mode">读取模式控制
        ///0x00: Idle模式 + Key A   
        ///0x01: All模式  + Key A
        ///0x02: Idle模式 + Key B  
        ///0x03: All模式  + Key B</param>
        /// <param name="blk_add">要读的块的起点地址, 范围从0--63</param>
        /// <param name="num_blk">要读的块数长度值, 范围从1—4（m1卡）   </param>
        /// <param name="snr">6个字节的密钥
        /// 如果成功，4 字节卡序列号 (从低到高)</param>
        /// <param name="buffer">  如果成功，buffer[0-N]: 从卡上返回的数据(16*num_blk字节)
        ///如果失败，buffer[0]: 返回状态，具体含义见附表。
        ///注：只能读取本扇区的块，因为每个扇区有自己独立的密钥
        ///成功返回0否则为非0, 具体含义见附表。</param>
        /// <returns></returns>
        [DllImport("All.dll", EntryPoint = "API_MF_Read")]
        static extern int API_MF_Read(IntPtr commHandle, int DeviceAddress, byte mode, byte blk_add, byte num_blk, byte[] snr, byte[] buffer);

        [DllImport("All.dll", EntryPoint = "API_MF_Write")]
        static extern int API_MF_Write(IntPtr commHandle, int DeviceAddress, byte mode, byte blk_add, byte num_blk, byte[] snr, byte[] buffer);

        [DllImport("All.dll", EntryPoint = "API_MF_GET_SNR")]
        static extern int API_MF_Get_Snr(IntPtr commHandle, int DeviceAddress, byte mode, byte cmd, ref byte flag, byte[] buffer);

        #endregion

        private IntPtr comPortHandle = IntPtr.Zero;

        /// <summary>
        /// 读卡器序列号，8个字节
        /// </summary>
        private ICItems serialNumber = new ICItems(8);
        public ICItems SerialNumber
        {
            get { return serialNumber; }
        }

        /// <summary>
        /// 读卡器编号
        /// </summary>
        private string deviceNumber;
        public string DeviceNumber
        {
            get { return deviceNumber; }
            set { deviceNumber = value; }
        }

        //串口号
        private int comPort;
        public int ComPort
        {
            get { return comPort; }
            set { comPort = value; }
        }

        //波特率
        private int baudRate;
        public int BaudRate
        {
            get { return baudRate; }
            set { baudRate = value; }
        }

        //是否读卡器已连接
        public bool IsConnected
        {
            get { return (comPortHandle != IntPtr.Zero); }
        }

        //错误信息
        private string message;
        public string Message
        {
            get { return message; }
        }

        public CardReader()
        {
        }


        /// <summary>
        /// 连接读卡器
        /// </summary>
        /// <returns></returns>
        public Boolean Connect()
        {
            Boolean result;
            comPortHandle = API_OpenComm(ComPort, BaudRate);
            if (comPortHandle == IntPtr.Zero)
            {
                result = false;
                message = "打开串口失败！";
            }
            else
            {
                result = true;
            }
            return result;
        }

        /// <summary>
        /// 断开读卡器
        /// </summary>
        /// <returns></returns>
        public Boolean DisConnect()
        {
            Boolean result;
            if (comPortHandle == IntPtr.Zero)
            {
                result = false;
                message = "串口未打开";
            }
            else
            {
                try
                {
                    if (API_CloseComm(comPortHandle))
                        result = true;
                    else
                    {
                        result = false;
                        message = "关闭串口失败";
                    }
                }
                catch (Exception ex)
                {
                    result = false;
                    message = ex.Message;
                }
            }
            return result;
        }

        /// <summary>
        /// 控制读卡器闪灯
        /// </summary>
        /// <param name="Freq"></param>
        /// <param name="Duration"></param>
        /// <returns></returns>
        public Boolean Flash(byte Freq, byte Duration)
        {
            Boolean result;
            byte buf = 0;
            if (API_ControlLED(comPortHandle, 0, Freq, Duration, ref buf) == 0)
                result = true;
            else
            {
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 控制读卡器鸣叫
        /// </summary>
        /// <param name="Freq"></param>
        /// <param name="Duration"></param>
        /// <returns></returns>
        public Boolean Beep(byte Freq, byte Duration)
        {
            Boolean result;
            byte buf = 0;
            if (API_ControlBuzzer(comPortHandle, 0, Freq, Duration, ref buf) == 0)
                result = true;
            else
            {
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 取得设备序列号
        /// </summary>
        /// <returns></returns>
        public Boolean GetDeviceSerialNumber()
        {
            Boolean result;
            byte[] buf = new byte[9];
            if (API_GetSerNum(comPortHandle, 0, buf) == 0)
            {
                for (int i = 1; i < 9; i++)
                {
                    serialNumber[i - 1] = buf[i];
                }
                result = true;
            }
            else
            {
                result = false;
                message = GetErrorMessage(buf[0]);
            }
            return result;
        }

        /// <summary>
        /// 设置设备序列号
        /// </summary>
        /// <param name="SN">设备序列号</param>
        /// <returns></returns>
        public Boolean SetDeviceSerialNumber(ICItems SN)
        {
            Boolean result = true;
            byte[] NewValue = new byte[8];
            byte buf = 0;

            for (int i = 0; i < 8; i++)
            {
                NewValue[i] = SN[i];
            }

            if (API_SetSerNum(comPortHandle, 0, NewValue, ref buf) == 0)
                result = true;
            else
                result = false;
            return result;
        }

        /// <summary>
        /// 选卡
        /// </summary>
        /// <param name="_Card"></param>
        /// <returns></returns>
        public Boolean SelectCard(ICS70 _Card)
        {
            Boolean result;
            if (comPortHandle == IntPtr.Zero)
            {
                result = false;
                message = "未连接读卡器！";
            }
            else
            {
                _Card.GetDeviceHandle(comPortHandle);
                result = true;
            }
            return result;
        }

        /// <summary>
        /// 读取IC卡的序列号
        /// </summary>
        /// <returns>buffer[0-3]: 4 字节卡序列号 (从低到高)</returns>
        public ICItems GetCardSerialNumber()
        {
            //读写模式
            //0x00：ALL模式
            //0x01：IDLE模式
            byte readMode = 0x01;

            //读写命令
            //0x00：不需要执行halt指令
            //0x01：执行halt指令
            //注意：老读卡器使用0x01，新的读卡器必须使用0x00。
            byte readCmd = 0x00;

            ICItems result = null;
            byte[] items = new byte[4];
            byte Flag = 0;
            if (API_MF_Get_Snr(comPortHandle, 0, readMode, readCmd, ref Flag, items) == 0)
            {
                result = new ICItems(4);
                for (int i = 0; i < 4; i++)
                {
                    result[i] = items[i];
                }
            }
            else
            {
                message = GetErrorMessage(Convert.ToInt32(items[0]));
            }
            return result;
        }

        /// <summary>
        /// 从Ini文件读取参数
        /// </summary>
        /// <returns></returns>
        public Boolean LoadSettingFromIni(string SettingsName)
        {
            Boolean result = false;
            IniSetting MySettings;
            string strComPort, strBaudRate;
            //连接读卡器，通过读卡器序列号，取得当前节点位置
            
            MySettings = new IniSetting(SettingsName);
            strComPort = MySettings.GetValue("CardReader", "ComPort");
            strBaudRate = MySettings.GetValue("CardReader", "BaudRate");
            if (!string.IsNullOrEmpty(strComPort) && !string.IsNullOrEmpty(strBaudRate))
            {
                ComPort = Convert.ToInt32(strComPort);
                BaudRate = Convert.ToInt32(strBaudRate);
                result = true;
            }
            return result;
        }

        /// <summary>
        /// 根据错误代码取得错误信息
        /// </summary>
        /// <param name="buf">错误代码</param>
        /// <returns></returns>
        private string GetErrorMessage(int buf)
        {
            string str;
            switch (buf)
            {
                case 0x00:
                    str = "命令执行成功\r\n";
                    break;
                case 0x01:
                    str = "命令操作失败（具体说明参见函数）\r\n";
                    break;
                case 0x80:
                    str = "参数设置成功\r\n";
                    break;
                case 0x81:
                    str = "参数设置失败\r\n";
                    break;
                case 0x82:
                    str = "通讯超时\r\n";
                    break;
                case 0x83:
                    str = "卡不存在\r\n";
                    break;
                case 0x84:
                    str = "接收卡数据出错\r\n";
                    break;
                case 0x85:
                    str = "输入参数或者输入命令格式错误\r\n";
                    break;
                case 0x87:
                    str = "未知的错误\r\n";
                    break;
                case 0x89:
                    str = "输入参数或者输入命令格式错误\r\n";
                    break;
                case 0x8A:
                    str = "在块初始化中出现错误\r\n";
                    break;
                case 0x8B:
                    str = "防冲突过程中得到错误的序列号\r\n";
                    break;
                case 0x8C:
                    str = "密码认证没有通过\r\n";
                    break;
                case 0x8f:
                    str = "输入的指令代码不存在\r\n";
                    break;
                case 0x90:
                    str = "卡不支持这个命令\r\n";
                    break;
                case 0x91:
                    str = "命令格式有错误\r\n";
                    break;
                case 0x92:
                    str = "在命令的FLAG参数中，不支持OPTION 模式\r\n";
                    break;
                case 0x93:
                    str = "要操作的BLOCK不存在\r\n";
                    break;
                case 0x94:
                    str = "要操作的对象已经被锁定，不能进行修改\r\n";
                    break;
                case 0x95:
                    str = "锁定操作不成功\r\n";
                    break;
                case 0x96:
                    str = "写操作不成功\r\n";
                    break;
                default:
                    str = "未定义的操作错误\r\n";
                    break;
            }
            return str;
        }

    }
    #endregion

    class IssuedCard
    {
        private string issuedNumber;
        public string IssuedNumber
        {
            get { return issuedNumber; }
            set { issuedNumber = value; }
        }

        public int CardID
        {
            get;
            set;
        }

        public int FlowID
        {
            get;
            set;
        }

        public string VehicleNumber
        {
            get;
            set;
        }

        public string DONumber
        {
            get;
            set;
        }

        public string Driver
        {
            get;
            set;
        }

        public string MobileNumber
        {
            get;
            set;
        }

        public string IDNumber
        {
            get;
            set;
        }

        public string Remark
        {
            get;
            set;
        }

        public string QueueNumber
        {
            get;
            set;
        }

        public DateTime TimeStamp
        {
            get;
            set;
        }

        public int IssueStatus
        {
            get;
            set;
        }

        public int SiteID
        {
            get;
            set;
        }

        public int UserID
        {
            get;
            set;
        }

        public string Company
        {
            get;
            set;
        }

        public string ToVisit
        {
            get;
            set;
        }

        public bool IsFirstTimeLimited
        {
            get;
            set;
        }

        public int PersonsOn
        {
            get;
            set;
        }

        public void Initial()
        {
            issuedNumber = "";
            SiteID = 0;
            QueueNumber = "";
            Remark = "";
            IDNumber = "";
            Driver = "";
            MobileNumber = "";
            DONumber = "";
            VehicleNumber = "";
            Company = "";
            ToVisit = "";
            CardID = 0;
            FlowID = 0;
            UserID = 0;
            PersonsOn = 0;
        }
    }

    class Site
    {
        /// <summary>
        /// 读卡点内部编码
        /// </summary>
        private int siteID;
        public int SiteID
        {
            get { return siteID; }
            set { siteID = value; }
        }

        /// <summary>
        /// 站点代码
        /// </summary>
        private string siteCode;
        public string SiteCode
        {
            get { return siteCode; }
            set { siteCode = value; }
        }

        /// <summary>
        /// 站点名称
        /// </summary>
        private string siteName;
        public string SiteName
        {
            get { return siteName; }
            set { siteName = value; }
        }

        /// <summary>
        /// 站点描述
        /// </summary>
        private string siteDescription;
        public string SiteDescription
        {
            get { return siteDescription; }
            set { siteDescription = value; }
        }

        private int passTimes;
        public int Passtimes
        {
            get { return passTimes; }
            set { passTimes = value; }
        }
    }
}
